在 Ethereum 虛擬機 (EVM) 中,我們已經介紹了各種操作碼 (opcodes)。這些操作碼是智能合約執行的基礎。在這一章中,我們將把這些操作碼組合起來,實現一個完整的 EVM。
EVM
類是整個虛擬機的核心,它負責執行智能合約的代碼。以下是其主要功能:
next
函數負責返回當前的操作碼並將程序計數器加一。execute
函數是 EVM 的主要循環,它會持續執行代碼直到達到終止條件。在 execute
函數中,EVM 會根據當前的操作碼調用相應的操作模組。
在 utils
中列出所有 opcode 和對應數字。
stack.Stack
函數;
arith.Arithmetic
函數;
comparison.Comparison
函數;
sha3env.Sha3Env
函數;
block.Block
函數;
storage.Storage
函數;
flow.Flow
函數;
log.Log
函數;
system.System
函數;
而這些 class 都在前面幾章有實現過,我後續會更新上更完整的 code 上來,目前還在調整和除 bug 中,嘿嘿~
在 main
函數中,我們創建了一個新的 EVM 實例,並執行了一段代碼。這段代碼只包含一個操作碼 0x40
,該操作碼對應於 BLOCKHASH
操作。執行後,我們可以打印堆疊的內容來查看結果。
import utils.opcodes as opcodes
from vm import (
stack,
arith,
comparison,
sha3env,
block,
storage,
flow,
log,
system
)
class EVM:
def __init__(self, code) -> None:
self.code = code
self.pc = 0
self.stack = []
self.memory = bytearray()
self.storage = {}
# Program Counter Return Execute Opcodes
def next(self):
opCode = self.code[self.pc]
self.pc += 1
return opCode
# Run EVM until code end
def execute(self):
while self.pc < len(self.code):
opCode = self.next()
# stack operations (50, 5F-7F, 80-8F, 90-9F)
if opcodes.PUSH0 <= opCode and opcodes.PUSH32 or \
opcodes.POP == opCode or \
opcodes.DUP1 <= opCode and opcodes.DUP16 or \
opcodes.SWAP1 <= opCode and opcodes.SWAP16:
stack.Stack(self, opCode)
# stop operations (00)
elif opcodes.STOP == opCode:
break
# arithmetic operations (01-0B)
elif opcodes.ADD <= opCode and opCode <= opcodes.SIGNEXTEND:
arith.Arithmetic(self, opCode)
# comparison & bitwise logic operations (10-1D)
elif opcodes.LT <= opCode and opCode <= opcodes.SAR:
comparison.Comparison(self, opCode)
# sha3 & enviroment operations (20, 30-3F)
elif opcodes.SHA3 <= opCode and opCode <= opcodes.EXTCODECOPY:
sha3env.Sha3Env(self, opCode)
# block operations (40-48)
elif opcodes.BLOCKHASH <= opCode and opCode <= opcodes.BASEFEE:
block.Block(self, opCode)
# memory & stack operations (51-55)
elif opcodes.MLOAD <= opCode and opCode <= opcodes.SSTORE:
storage.Storage(self, opCode)
# flow operations (56-5B)
elif opcodes.JUMP <= opCode and opCode <= opcodes.JUMPDEST:
flow.Flow(self, opCode)
# log operations (A0-A4)
elif opcodes.LOG0 <= opCode and opCode <= opcodes.LOG4:
log.Log(self, opCode)
# system operations (F0-FF)
elif opcodes.CREATE <= opCode and opCode <= opcodes.SELFBALANCE:
system.System(self, opCode)
else:
raise("Invalid Opcodes")
# main
if __name__ == '__main__':
code = b"\x40"
evm = EVM(code)
evm.execute()
print(evm.stack)
這就是目前 EVM 虛擬機完整實現,我們接下來要用 python 實現個 proof system 來證明該 EVM 行為的一致。
等鐵人賽 30 天,我會將完整 EVM monorepo 開源,便可使用該系統來 run 一部分的 solidity code 並觀看stack 狀態,接下來剩下一半的賽程會教大家如何將這些指令用 zk 來 proof 該行為是正確的,會比較偏理論一點,也會帶 code 來證明。